package megrez.bussiness.schedule.component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import megrez.bussiness.schedule.entity.Job;
import megrez.bussiness.schedule.service.JobService;
import megrez.bussiness.schedule.util.ScheduleErrorCode;
import megrez.bussiness.schedule.util.ScheduleException;

/**
 * 任务注册
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@Component
@RequiredArgsConstructor
public class CronTaskRegistrar implements DisposableBean {

    private final Map<Long, ScheduledFuctureHolder> scheduledTaskMap = new ConcurrentHashMap<>(16);

    private final TaskScheduler taskScheduler;
    private final JobService jobService;

    public void addTask(Job job) {
        if (this.scheduledTaskMap.containsKey(job.getId())) {
            throw new ScheduleException(ScheduleErrorCode.SCHEDULE_TASK_EXIST);
        }

        try {
            SchedulingTask task = SchedulingTask.of(job, jobService);
            addTask(task);
        } catch (ClassNotFoundException e) {
            throw new ScheduleException(ScheduleErrorCode.CLASS_NOT_FOUND_IN_SPRING, e);
        }
        
    }

    protected synchronized void addTask(SchedulingTask task) {
        if (task == null) {
            return;
        }
        if (this.scheduledTaskMap.containsKey(task.info.jobId)) {
            return;
        }

        try {
            CronTask cronTask = new CronTask(task, task.info.cronExpression);
            ScheduledFuture<?> future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
            this.scheduledTaskMap.put(task.info.jobId, new ScheduledFuctureHolder(task, future));
        } catch (Exception e) {
            throw new ScheduleException(ScheduleErrorCode.SCHEDULE_TASK_START_FAIL, e);
        }

    }

    public boolean containTask(Long jobId) {
        return scheduledTaskMap.containsKey(jobId);
    }

    public void removeCronTask(Long jobId) {
        ScheduledFuctureHolder hoder = this.scheduledTaskMap.remove(jobId);
        if (hoder != null) {
            hoder.cancelTask();
        }
    }

    @Override
    public void destroy() {
        for (ScheduledFuctureHolder hoder : this.scheduledTaskMap.values()) {
            hoder.cancelTask();
        }

        this.scheduledTaskMap.clear();
    }

}
